package com.jacksay.vikingfl.synchro
{
	public class VOPipeProperty
	{
		
		// -----------------------------------------------------------------------------
		// convertForCompareFunction
		// -----------------------------------------------------------------------------
		/**
		 * Fonction a appliquer à la donnée avant de faire la comparaison.
		 * 
		 * @default null
		 * @author jacksay14
		 * @date 2009-12-14
		 */ 
		[Inspectable(defaultValue=null,verbose=1,category=Other)]
		public function get convertForCompareFunction () :Function{
			return _convertForCompareFunction;
		}
		
		/**
		 * @private
		 */
		private var _convertForCompareFunction:Function = null;
		
		/**
		 * @private
		 */
		public function set convertForCompareFunction( value:Function ) :void {
			_convertForCompareFunction = value;
		}
		
		

		// ------------------------------------------------------------------
		// dataNameInView
		// ------------------------------------------------------------------
		/**
		 * Nom de la propriété dans la vue
		 *
		 * @default null
		 * @since 2009-12-11
		 * @author jacksay14
		 */
		[Inspectable(category="Other", defaultValue=null, enumeration="",type="String")]
		public function get dataNameInView() :String {
			return _dataNameInView;
		}
		
		/**
		 * @private
		 */
		private var _dataNameInView:String = null;
		
		/**
		 * @private
		 */
		public function set dataNameInView( value:String ) :void {
			_dataNameInView = value;
		}
		
		
		
		// -----------------------------------------------------------------------------
		// dataNameInHost
		// -----------------------------------------------------------------------------
		/**
		 * Nom de l'ascesseur pour la donné dans le host
		 * 
		 * @default null
		 * @author Stéphane
		 * @date 2009-12-11
		 */ 
		[Inspectable(defaultValue=null,verbose=1,category=Other,type=String)]
		public function get dataNameInVO () :String{
			return _dataNameInVO;
		}
		
		/**
		 * @private
		 */
		private var _dataNameInVO:String = null;
		
		/**
		 * @private
		 */
		public function set dataNameInVO( value:String ) :void {
			_dataNameInVO = value;
		}


		
		// -----------------------------------------------------------------------------
		// dataEventInHost
		// -----------------------------------------------------------------------------
		/**
		 * Type d'événement difusé lors du changement de la propriété
		 * 
		 * @default null
		 * @author Stéphane
		 * @date 2009-12-11
		 */ 
		[Inspectable(defaultValue=null,verbose=1,category=Other,type=String)]
		public function get dataEventInHost () :String{
			return _dataEventInHost;
		}
		
		/**
		 * @private
		 */
		private var _dataEventInHost:String = null;
		
		/**
		 * @private
		 */
		public function set dataEventInHost( value:String ) :void {
			_dataEventInHost = value;
		}


		
		
		public function VOPipeProperty(nameInView:String, nameInVO:String, eventChange:String, convertFunction:Function=null)
		{
			dataEventInHost = eventChange;
			dataNameInView = nameInView;
			dataNameInVO = nameInVO;
			convertForCompareFunction = convertFunction;
		}
		
		public function get userData() :* {
			return _dataUser;
		}
		
		public function get initialData() :* {
			return _dataInitial;
		}
		
		public function get incomingData() :* {
			return _dataIncoming;
		}
		
		public function hasUserChange() :Boolean {
			return getDataCompare(_dataInitial) != getDataCompare(_dataUser);
		}
		
		
		private var _dataInitial:*;
		private var _dataUser:*;
		private var _dataIncoming:*;
		
		
		/**
		 * Retourne la donnée pour comparaison
		 * 
		 * @param value Donnée
		 * @return Donnée convertie
		 */
		protected function getDataCompare( value:* ) :* {
			if( convertForCompareFunction == null ){
				return value;
			} else {
				return convertForCompareFunction(value);
			}
		}
		
		
		/**
		 * Evalue la donnée utilisateur et la donnée initiale, si elles sont 
		 * diférentes, retourne <code>true</code>, sinon retourne 
		 * <code>false</code>.
		 * 
		 * @return Boolean;
		 */
		internal function checkUserChange() :Boolean {
			return getDataCompare(_dataInitial) != getDataCompare(_dataUser );
		}
		
		
		
		/**
		 * VoPipeProperty.NO_CHANGE La donnée initiale n'a pas changée, et n'a 
		 * pas été modifiée par l'utilisateur.
		 */
		internal static const NO_CHANGE:int = 0;
		
		
		
		/**
		 * VoPipeProperty.CHANGE_BY_USER La donnée initiale n'a pas changée, l'
		 * utilisateur l'a modifié, on met a jour la donnée initial uniquement.
		 */
		internal static const CHANGE_BY_USER:int = 1;
		
		
		
		/**
		 * VoPipeProperty.CHANGE_BY_INCOMING La donnée initiale a changée, l'
		 * utilisateur ne l'a  pas modifié, on met a jour la donnée initiale. Un
		 * refresh est necessaire.
		 */
		internal static const CHANGE_BY_INCOMING:int = 2;
		
		
		
		/**
		 * VoPipeProperty.CHANGE_ALL La donnée initiale a changée, l'
		 * utilisateur l'a  changé, on ouvre un modal à l'utilisateur pour qu'il 
		 * décide quoi faire.
		 */
		internal static const CHANGE_ALL:int = 3;
		
		
		
		/**
		 * Evalue les modifications de donnée et retourne un int déterminant 
		 * l'action à appliquer.
		 */
		internal function synchronize() :int {
			var initial:* = getDataCompare(_dataInitial);
			var incoming:* = getDataCompare(_dataIncoming);
			var user:* = getDataCompare(_dataUser);
			
			// Donnée modifiée par l'utilisateur
			if( user != initial ){
				
				// Et est différente de la donnée à synchronizer
				// La synchro se fera dans une boite modale
				if( initial != incoming ){
					return CHANGE_ALL;
				}
				
				else {
					return CHANGE_BY_USER;
				}
			} 
			
			// L'utilisateur n'a rien changé
			else {
				
				// La donnée initial a changé
				if( initial != incoming ){
					return CHANGE_BY_INCOMING;
				} 
				
				// Aucun changement
				else {
					return NO_CHANGE;
				}
				
			}
		}
		
		internal function applySynchro( level:int, response:int=-1 ) :void {
			if( level < 2 ) return;
			else if (level == 2 ){
				_dataInitial = _dataIncoming;
				_dataUser = _dataIncoming;
			}
			
			else if ( level == 3 ){
				if( response == -1 ){
					trace("Pas de synchro");
				}
				
				else if( response == 0 ){
					trace("On met juste à jour la donnée initiale mais on concerve la donnée utilisateur");
					_dataInitial = _dataIncoming;
				}
				
				else if ( response == 1 ){
					_dataInitial = _dataIncoming;
					_dataUser = _dataIncoming;
				}
			}
		}
		
		
		
		/**
		 * Modification de la donnée utilisateur, cette fonction est executée
		 * lorsque qu'un événement relatif à une modification surviens dans le 
		 * host.
		 * 
		 * @param value
		 * @return Boolean Si la donnée entrée par l'utilisateur est différente
		 * de la donnée initiale, retourne <code>true</code>, sinon retourne 
		 * <code>false</code>
		 */
		internal function userDataUpdate( value:* ) :void {
			if( getDataCompare(value) != getDataCompare(_dataUser) ){
				trace("User change property " +dataNameInVO +" hosted by "+dataNameInView+" ( = "+_dataInitial+") to " +value);
				_dataUser = value;
			}
		}
		
		
		
		/**
		 * 
		 */
		internal function setIncomingData( value:* ) :void {
			if( getDataCompare(value) != getDataCompare(_dataIncoming) ){
				trace("Incoming data change from " + _dataInitial +" to " +_dataIncoming);
				_dataIncoming = value;
			}
		}
		
		
		
		/**
		 * Initialize la donnée initial
		 */		
		internal function initInitialData( value:* ) :void {
			if( value != _dataInitial ){
				trace("INIT DATA ("+dataNameInVO+") = " +value);
				_dataInitial = value;
				_dataIncoming = value;
				_dataUser = value;
			}
		}
		
		

	}
}